討論邏輯運算子(logical operators)與位元運算子(bitwise operators)的使用情境
Part I. logical operators
Part II. bitwise operators (1)
Part II. bitwise operators (2)
Part II. bitwise operators (3)
logical operators 跟 bitwise operators長得很像,但所代表的意思與用法卻是天差地別。
一般來說,我們對 logical operators 比較熟悉, logical operators 包括&&, || 與 !。
expr1 && epxr2: and,也就是兩邊的運算式必須全部都為 true。
expr1 || expr2: or,兩邊的運算式只要一邊為 true即可。
!expr: not,!true=false, !false=true
logical operators 一般是用在流程控制,比較特別的用法就是用在設值的時候,像是 || 可以用來設定預設值,常用的情境是物件中的屬性是否有被設定,這用來寫模組的時候非常好用。
var name = user.name || "unknown";
另外很常遇到的情況是需要一個條件判斷後來設定值,一般會用 ?:,但也可以用 &&。
var height = height > 100 ? height : 100;
// 設置最小高度
if(height < 100)
height = 100;
// 可以寫成:
(height < 100) && (height = 100);
另外一個情境是企圖想要從 undefined 中取值時:
var user = {};
// 會有 exception
var lastname = user.name.last;
// 會得到一個 undefined,但不會有 exception
var firstname = user.name && user.name.first;
為什麼可以這樣做?
這是因為 || 與 && 的特性,仔細想一下這兩者的定義為何。
|| 是兩邊的運算式只要一邊為 true即可,所以當第一個 expr1 為 true 的話,就不用再去驗證 expr2 是否為 true 了,反過來說,當 expr1 為 false 的時候,就還要繼續去看一下 expr2 的結果。會有這樣的特性是因為可以節省一些執行效率,既然expr1已經是true了,|| 又只要一個運算式是 true 就好,那又何必再去驗證expr2呢?可以省下一個運算式。
而我們在做預設值設定的時候,就是要看看這個參數的值是否已經被設定了(expr1),當這個值有被設定時就用設定的值,如果沒有,就採用預設的值(expr2)。這跟 || 的定義是不是很像呢?
var name = user.name || "unknown";
// ^^^^^^^^^^ ^^^^^^^^^
// expr1 expr2
如果 user.name有設定值(註1)的話,會回傳 true(更正確的說法是回傳 expr1 的值),那||就不用再去驗證 expr2;如果 user.name 沒有設值的話(註1),會回傳false,那||就會再去驗證 expr2(也就是執行 expr2,回傳 epxr2的值)。
我們再來看一下JavaScript: The Good Parts中對||的解釋:
如果第一個運算式估算為 true,|| 會產生它的第一個運算式的值。否則產生第二個運算式的值。 from JavaScript: The Good Parts
看過這個說法後,是不是有更清楚了一些呢?
&&也是一樣的道理,它基本的定義是兩邊的運算式必須全部都為true,因為是要求兩邊的運算是都要為true,所以當epxr1為true時,仍然需要去檢查expr2,但相反的,當expr1為false時,就可以拋出false了,不需要再去驗證epxr2。
(height < 100) && (height = 100);
//^^^^^^^^^^^ ^^^^^^^^^^^^^
// epxr1 expr2
當epxr1條件成立時,才會去執行expr2,這不就是我們原本要的嗎?
一樣我們來看一下JavaScript: The Good Parts中對 && 的解釋:
如果第一個運算式估算為false,&& 會產生它的第一個運算式的值。否則產生第二個運算式的值。 from JavaScript: The Good Parts
註1: 這邊的user.name是字串,留意在javascript中,false, null, undefined, 空字串'', 數值0與數值NaN會被視為false。